﻿using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using C4F.VistaP2P.Common;

namespace C4F.VistaP2P.WPF.Picture
{
    /// <summary>
    /// Interaction logic for Picture.xaml
    /// </summary>
    
    public partial class PictureControl : UserControl
    {
        /// <summary>
        /// Just default constructor that shows the PictureControl
        /// </summary>
        public PictureControl()
        {
            InitializeComponent();                    
        }

        /// <summary>
        /// When the picture control is loaded hook up the default controls if nothing was set
        /// automatically.
        /// </summary>
        /// <param name="sender">unused</param>
        /// <param name="e">unused</param>
        private void _PictureControlLoaded(object sender, RoutedEventArgs e)
        {
            if (SendPictureButton == null)
            {
                SendPictureButton = btnSendPicture;
            }
           
            if (PictureBox == null)
            {
                PictureBox = image1;
            }

            if (TitleName == null)
            {
                TitleName = lblFileTitle;
            }

            if (FileName == null)
            {
                FileName = lblFileName;
            }

            SendPictureButton.IsEnabled = false;

        }

        #region public methods and events to use when completely overriding this control

        /// <summary>
        /// Used to send a picture given the path and filename
        /// </summary>
        /// <param name="fullPathAndFileName">the path and filename</param>
        public void SendPicture(string fullPathAndFileName)
        {
            //send it in another thread so the UI thread remains responsive...  
            if (fullPathAndFileName != null && System.IO.File.Exists(fullPathAndFileName))
            {
                using (FileStream fs = new FileStream(fullPathAndFileName, FileMode.Open))
                {
                    PicturePacket packet = new PicturePacket();
                    packet.s = fs;
                    packet.fileName = System.IO.Path.GetFileName(fullPathAndFileName);
                    MetadataFileInfo md = new MetadataFileInfo();
                    md.ReadMetaData(fullPathAndFileName);
                    packet.title = md.Title;
                    
                    if (SendingPicture != null)
                    {
                        SendingPicture(this, new PictureChangedEventArgs(packet));
                    }
                }
            }
            else
            {
                throw new ApplicationException(string.Format("File not found: {0}", fullPathAndFileName));
            }
        }

        /// <summary>
        /// register for this event if you want to be notified when a picture is received
        /// </summary>
        public event EventHandler<PictureChangedEventArgs> PictureReceived;
        
        /// <summary>
        /// register for this event if you want to be notified when the status is changed.
        /// </summary>
        public event EventHandler<StatusChangedEventArgs> StatusChanged;


        #endregion

        /// <summary>
        /// The dependency property for the Picture control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static DependencyProperty SendPictureButtonProperty = DependencyProperty.Register(
           "SendPictureButton", typeof(Button), typeof(PictureControl), new PropertyMetadata(null, new PropertyChangedCallback(_SendPictureButtonPropertyChanged)));

        /// <summary>
        /// set and get the Picture control.
        /// </summary>
        public Button SendPictureButton
        {
            get
            {
                try
                {
                    return (Button)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Send,
                       (DispatcherOperationCallback)delegate { return GetValue(SendPictureButtonProperty); },
                       SendPictureButtonProperty);
                }
                catch
                {

                    return (Button)SendPictureButtonProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(SendPictureButtonProperty, value); },
                  value);
            }
        }

        /// <summary>
        /// When the Send Picture Button changes update the event _SendPictureButton_Click.
        /// </summary>
        /// <param name="d">the PictureControl</param>
        /// <param name="e">the old and new button</param>
        private static void _SendPictureButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            PictureControl pc = (PictureControl)d;
            if (e.OldValue != null)
            {
                //unregister from the old one...
                Button ob = (Button)e.NewValue;
                ob.Click -= new RoutedEventHandler(pc._SendPictureButton_Click);
            }
            //register for the new events.
            Button nb = (Button)e.NewValue;
            nb.Click += new RoutedEventHandler(pc._SendPictureButton_Click);
        }

        /// <summary>
        /// The dependency property for the PictureBox control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static DependencyProperty PictureBoxProperty = DependencyProperty.Register(
          "PictureBox", typeof(System.Windows.Controls.Image), typeof(PictureControl));
        
        /// <summary>
        /// set and get the PictureBox control.
        /// </summary>
        public System.Windows.Controls.Image PictureBox
        {
            get
            {
                try
                {
                    return (System.Windows.Controls.Image)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(PictureBoxProperty); },
                       PictureBoxProperty);
                }
                catch
                {

                    return (System.Windows.Controls.Image)PictureBoxProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(PictureBoxProperty, value); },
                  value);
            }
        }

        /// <summary>
        /// The dependency property for the FileName label control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static DependencyProperty FileNameProperty = DependencyProperty.Register(
         "FileName", typeof(Label), typeof(PictureControl));

        /// <summary>
        /// set and get the FileName control.
        /// </summary>
        public Label FileName
        {
            get
            {
                try
                {
                    return (Label)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(FileNameProperty); },
                       FileNameProperty);
                }
                catch
                {

                    return (Label)FileNameProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(FileNameProperty, value); },
                  value);
            }
        }

        /// <summary>
        /// The dependency property for the TitleName control. The dependency property is used so we can have databinding using the smart tag adorner
        /// </summary>
        public static DependencyProperty TitleNameProperty = DependencyProperty.Register(
         "TitleName", typeof(Label), typeof(PictureControl));
        
        /// <summary>
        /// set and get the TitleName control. This is the label on top of the control.
        /// </summary>
        public Label TitleName
        {
            get
            {
                try
                {
                    return (Label)this.Dispatcher.Invoke(
                       System.Windows.Threading.DispatcherPriority.Normal,
                       (DispatcherOperationCallback)delegate { return GetValue(TitleNameProperty); },
                       TitleNameProperty);
                }
                catch
                {

                    return (Label)TitleNameProperty.DefaultMetadata.DefaultValue;
                }
            }
            set
            {
                Dispatcher.Invoke(DispatcherPriority.Normal,
                  (SendOrPostCallback)delegate { SetValue(TitleNameProperty, value); },
                  value);
            }
        }


        /// <summary>
        /// The NetworkManager registers for this event to listen for when the control is sending a picture.
        /// </summary>
        internal event EventHandler<PictureChangedEventArgs> SendingPicture;
        
        /// <summary>
        /// This function is called when the user clicks on the SendPictureButton
        /// </summary>
        /// <param name="sender">unused</param>
        /// <param name="e">unused</param>
        private void _SendPictureButton_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd;
            ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.FileName = "openFileDialog1";
            ofd.Filter = "(*.JPG, *.GIF, *.PNG)|*.jpg;*.gif;*.png|All Files (*.*)|*.*";
            ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            ofd.RestoreDirectory = true;
            ofd.Title = "Select a Picture";


            //check return value, but how in wpf?
            bool ok = (bool)ofd.ShowDialog();

            if (ok)
            {
                SendPicture(ofd.FileName);                                   
            }
        }


        /// <summary>
        /// This delegate is used to ensure that the function SetStatusChanged is called on the thread that owns the
        /// SendPictureButton
        /// </summary>
        /// <param name="userName">the username of the network manager</param>
        /// <param name="e">contains information on how the status changed.</param>
        private delegate void _StatusChangedHandler(string userName, StatusChangedEventArgs e);

        /// <summary>
        /// This function is called by the NetworkManager when the status of the network changes.
        /// 
        /// </summary>
        /// <param name="userName">the username of the network manager</param>
        /// <param name="e">contains information on how the status changed.</param>
        internal void SetStatusChanged(string userName, StatusChangedEventArgs e)
        {
            if (SendPictureButton.CheckAccess())
            {
                if (userName == e.Member && e.NewNodeJoined)
                {
                    SendPictureButton.IsEnabled = true;
                }

                if (userName == e.Member && e.NodeLeft)
                {
                    SendPictureButton.IsEnabled = false;
                }

                //let anyone else know if they registered for the event.
                if (null != StatusChanged)
                {
                    StatusChanged(userName, e);
                }
            }
            else
            {
                SendPictureButton.Dispatcher.Invoke(DispatcherPriority.Normal, new _StatusChangedHandler(SetStatusChanged), userName, e );
            }
        }

        /// <summary>
        /// This delegate is used to ensure that the function SetNewPicture is called on the thread that owns the
        /// PictureBox control
        /// </summary>
        /// <param name="userName">the username of the network manager</param>
        /// <param name="e">contains information on how the status changed.</param>
        delegate void SetNewPictureHandler(PictureChangedEventArgs packet);

        /// <summary>
        /// Sets the new picture.
        /// </summary>
        /// <param name="e"></param>
        internal void SetNewPicture(PictureChangedEventArgs e)
        {
            if (PictureBox.CheckAccess())
            {
                Byte[] b = new Byte[C4F.VistaP2P.Common.PictureHelper.MAX_IMAGE_SIZE];
                int curPos = 0;
                int val = 0;
                do
                {
                    if (e.Packet.s.CanRead)
                    {
                        val = e.Packet.s.Read(b, curPos, C4F.VistaP2P.Common.PictureHelper.MAX_IMAGE_SIZE - curPos);
                        curPos += val;
                    }
                    else
                    {
                        throw new ApplicationException("Unable to Read the Picture Stream");
                    }
                } while (val != 0);

                MemoryStream ms = new MemoryStream();
                ms.Write(b, 0, curPos);
                ms.Position = 0;

             
                System.Windows.Media.Imaging.BitmapImage bim = new System.Windows.Media.Imaging.BitmapImage();
                bim.BeginInit();
                bim.StreamSource = ms;
                bim.EndInit();
                PictureBox.Source = bim;

                Utility.SetLabelText(FileName, e.Packet.fileName);
                Utility.SetLabelText(TitleName, e.Packet.title);

                
                if (PictureReceived != null)
                {                
                    PictureReceived(this, e);
                }                                
            }
            else
            {
                // Invocation required
                PictureBox.Dispatcher.Invoke(DispatcherPriority.Normal, new SetNewPictureHandler(SetNewPicture), e);
            }
        }
    }

   
}
